package org.emerald.katabankocr;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class KataBankOCR {

	String lineSeparator = System.getProperty("line.separator");

	public class KataBankOCRException extends Exception {

		private static final long serialVersionUID = 1L;

		public KataBankOCRException(String message) {
			super(message);
		}

	}

	final static String[] oCRDigits = { " _ | ||_|", "     |  |", " _  _||_ ",
			" _  _| _|", "   |_|  |", " _ |_  _|", " _ |_ |_|", " _   |  |",
			" _ |_||_|", " _ |_| _|" };

	protected KataBankOCR() {

	}

	protected String convertCharacter(String OCRString) {
		for (int i = 0; i <= 9; i++)
			if (oCRDigits[i].equals(OCRString))
				return Integer.toString(i);

		return "?";

	}

	protected StringBuilder[] getOCRCharactersFromLineOfOCRCharacters(
			String lineOfOCRCharacters) {

		StringBuilder[] oCRCharacters = new StringBuilder[9];
		for (int i = 0; i < 9; i++)
			oCRCharacters[i] = new StringBuilder();

		for (int line = 0; line < 3; line++) {
			for (int charIndex = 0; charIndex < 9; charIndex++) {
				int startIndex = (charIndex * 3) + (line * 27);
				int endIndex = startIndex + 3;
				oCRCharacters[charIndex].append(lineOfOCRCharacters.substring(
						startIndex, endIndex));
			}
		}

		return oCRCharacters;
	}

	protected String getAccountNumberFromLine(String lineOfOCRCharacters) {
		StringBuilder[] arrayOfOCRCharacters = getOCRCharactersFromLineOfOCRCharacters(lineOfOCRCharacters);

		StringBuilder returnAccountNumber = new StringBuilder();

		for (StringBuilder OCRCharacter : arrayOfOCRCharacters)
			returnAccountNumber
					.append(convertCharacter(OCRCharacter.toString()));

		return returnAccountNumber.toString();
	}

	protected String[] getAccountNumbersFromString(String OCRCharacters)
			throws KataBankOCRException {

		int lengthOfLine = 27 * 3;
		String OCRCharactersWithoutNewLine = OCRCharacters.replaceAll(
				lineSeparator, "");

		if (OCRCharactersWithoutNewLine.length() % 27 != 0)
			throw new KataBankOCRException("The File is not properly formatted");

		List<String> returnAccountNumbers = new ArrayList<String>();

		int numberOfLines = OCRCharactersWithoutNewLine.length() / lengthOfLine;

		for (int line = 0; line < numberOfLines; line++) {
			int startIndex = line * lengthOfLine;
			int endIndex = startIndex + lengthOfLine;
			String OCRLineToBeConverted = OCRCharactersWithoutNewLine
					.substring(startIndex, endIndex);
			returnAccountNumbers
					.add(getAccountNumberFromLine(OCRLineToBeConverted));
		}

		return returnAccountNumbers.toArray(new String[0]);
	}

	public String[] getAccountNumbersFromFile(String fileName)
			throws IOException, KataBankOCRException {
		File scannedFile = new File(fileName);

		if (!scannedFile.exists())
			throw new FileNotFoundException("File " + fileName
					+ " doesn't exist");

		BufferedReader reader = new BufferedReader(new FileReader(fileName));

		String lineOfData;
		StringBuilder fileData = new StringBuilder();

		while ((lineOfData = reader.readLine()) != null)
			fileData.append(lineOfData);

		return getAccountNumbersFromString(fileData.toString());

	}

	protected int[] convertAccountNumberToIntegerArray(String accountNumber) {
		int[] returnAccountNumber = new int[9];
		for (int i = 0; i < 9; i++)
			returnAccountNumber[i] = Integer.parseInt(accountNumber.substring(
					i, i + 1));

		return returnAccountNumber;

	}

	protected boolean validateAccountNumber(String accountNumber) {
		int[] accountNumberAsIntArray = convertAccountNumberToIntegerArray(accountNumber);

		int sum = 0;

		for (int i = 0; i < 9; i++) {
			sum += accountNumberAsIntArray[i] * (9 - i);
		}

		if (sum % 11 == 0)
			return true;
		else
			return false;
	}

	protected boolean isIllFormed(String accountNumber) {
		if (accountNumber.indexOf("?") == -1)
			return false;
		else
			return true;
	}

	public void getAccountNumbersFromFileAndWriteToReadableFile(
			String scannedFileName, String outputFileName) throws IOException,
			KataBankOCRException {
		String[] accountNumbers = this
				.getAccountNumbersFromFile(scannedFileName);

		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(
				outputFileName));

		for (String accountNumberString : accountNumbers) {

			if (isIllFormed(accountNumberString))
				bufferedWriter.write(accountNumberString + " ILL"
						+ lineSeparator);
			else {
				if (this.validateAccountNumber(accountNumberString))
					bufferedWriter.write(accountNumberString + lineSeparator);
				else
					bufferedWriter.write(accountNumberString + " ERR"
							+ lineSeparator);

			}
		}

		bufferedWriter.flush();

		bufferedWriter.close();

	}

}
